#include "screen.h"
#include "i8259.h"
#include <types.h>

#define LATCH 1193180
#define HZ 100

void handler_init();
void pit_init();

static inline void
outb(unsigned short port, unsigned char value)
{
     asm("outb %1,%0;" : "=d"(port) : "r"(value));
}

static inline unsigned char
inb(unsigned short port)
{
     unsigned char data;
     asm("inb %1,%0;":"=a"(data):"d"(port));
     return data;
}

struct gatedesc {
     unsigned long offset_low : 16;
     unsigned long selector : 16;
     unsigned long : 8;
     unsigned long type : 4;
     unsigned long : 1;
     unsigned long dpl : 2;
     unsigned long present : 1;
     unsigned long offset_high : 16;
};

static struct gatedesc vector[256];

void pic_init(void)
{
     /* set mask */
     outb(0x21, 0xff);
     outb(0xa1, 0xff);

     outb(0x20, 0x11);		/* ICW1 master */
     outb(0x21, 0x20);		/* ICW2 master */
     outb(0x21, 0b10);		/* ICW3 master */
     outb(0x21, 0x3);		/* ICW4 master */

     outb(0xa0, 0x11); 		/* ICW1 slave */
     outb(0xa1, 0x28); 		/* ICW2 */
     outb(0xa1, 0x2);		/* ICW3 */
     outb(0xa1, 0x3);		/* ICW4 */

     /* outb(0x20, 0x68); */
     /* outb(0x20, 0x0a); */
     /* outb(0xa0, 0x68); */
     /* outb(0xa0, 0x0a); */

     outb(0x21, 0xfc);
     outb(0xa1, 0x0);

     pit_init();

     init_idt();
     handler_init();
     return;
}

void pit_init()
{
     outb(0x43, 0b00110110); 	/* channel 0 mode 3 */
     uint16 data = LATCH / HZ;
     outb(0x40, (uint8)(data & 0xFF));
     outb(0x40, (uint8)((data >> 8) & 0xFF));
}

void* memset(void* s, int c, unsigned n)
{
     int i;
     for (i = 0; i < n; i++)
     {
	  *(char*)(s + i) = c;
     }

     return s;
}

void keybd_handler()
{
     unsigned char kbdata = inb(0x60);
     disp_hex(kbdata);
    
     return;
}

void pit_handler()
{
     static int counter = 0;
     counter++;
     if (counter == 100)
     {
	  puts("100 ticks occered.\n");
	  counter = 0;
     }
}

void set_int_gate(int gateno, void* addr)
{
     vector[gateno].offset_low = (unsigned) addr;
     vector[gateno].offset_high = (unsigned) addr >> 16;
     vector[gateno].selector = 0b10000;
     vector[gateno].type  = 0xe;
     vector[gateno].dpl = 0;
     vector[gateno].present = 1;

     return;
}
     
void init_idt()
{

     memset(vector, 0, sizeof(vector));

     extern long isr;

     int i;

     for(i = 0; i < 256; i++)
     {
	  /* vector[i].offset_low = (unsigned) &isr; */
	  /* vector[i].offset_high = (unsigned)(&isr) >> 16; */
	  /* vector[i].selector = 0b10000; */
	  /* vector[i].type  = 0xe; */
	  /* vector[i].dpl = 0; */
	  /* vector[i].present = 1; */
	  set_int_gate(i,&isr);
     }

     extern long isr0, isr1, gp, isr6;
     set_int_gate(0x21, &isr1);
     set_int_gate(13, &gp);
     set_int_gate(6, &isr6);
     set_int_gate(0x20, &isr0);
     
     unsigned idt48[2];
     idt48[0] = sizeof(vector) << 16;
     idt48[1] = (unsigned)vector;
     
     asm volatile("lidt (%0);sti;"::"r"((char*) idt48 + 2));
     
     
     return;
}

